package com.bes.bessdk.service.base;

import android.util.Log;

import com.bes.bessdk.BesSdkConstants;
import com.bes.bessdk.utils.ArrayUtil;
import com.bes.bessdk.utils.sha.Sha256;
import com.bes.bessdk.utils.sha.aes;
import com.bes.bessdk.utils.sha.besFunc;

import java.util.Random;

public class TOTAConnectCMD {
    byte[] random_b;
    byte[] random_a;
    byte[] aes_key;
    byte[] hash_key_b;
    byte[] cashData = new byte[0];
    byte[] cashReceiveData = new byte[0];

    byte[] head = ArrayUtil.toBytes(ArrayUtil.str2HexStr("HEAD"));
    byte[] tail = ArrayUtil.toBytes(ArrayUtil.str2HexStr("TAIL"));
    byte[] dataLen = new byte[4];
    byte[] crc = new byte[4];

    public byte[] totaStartData() {
        int random_length = new Random().nextInt(128 - 16) + 16;
        random_b = new byte[random_length];
        new Random(new Random().nextInt(10000)).nextBytes(random_b);
        byte[] bytes = new byte[random_length + 5];
        byte[] cmdlength = ArrayUtil.intToBytesLittle(random_length + 1);
        System.arraycopy(random_b, 0, bytes, 5,random_length);
        bytes[0] = 0x01;
        bytes[1] = 0x10;
        bytes[2] = cmdlength[0];
        bytes[3] = cmdlength[1];
        bytes[4] = (byte) random_length;
        return bytes;
    }

    public byte[] totaConfirm() {
        byte[] bytes = new byte[hash_key_b.length + 4 + 1];
        System.arraycopy(hash_key_b, 0, bytes, 4 + 1,hash_key_b.length);
        bytes[0] = 0x03;
        bytes[1] = 0x10;
        bytes[2] = (byte) 0x21;
        bytes[3] = 0x00;
        bytes[4] = (byte) 0x20;
        return bytes;
    }

    public byte[] totaEncryptData(byte[] data) {
        return aes.encrypt(data, aes_key);
    }

    public byte[] totaDecodeData(byte[] data) {
        return aes.decrypt(data, aes_key);
    }

    public byte[] getTotaV2Packet(byte[] data) {
        byte[] crc = new byte[4];
        byte[] dataLen = ArrayUtil.intToBytesLittle(data.length);
        long crc32 = ArrayUtil.crc32(data, 0, data.length);
        crc[0] = (byte) crc32;
        crc[1] = (byte) (crc32 >> 8);
        crc[2] = (byte) (crc32 >> 16);
        crc[3] = (byte) (crc32 >> 24);

        byte[] bytes = ArrayUtil.bytesSplic(ArrayUtil.byteMerger(head, dataLen), data, crc, tail);
        return bytes;
    }

    public byte[] getTotaV2PacketData(byte[] cmdCode, byte[] param) {
        if (cmdCode == null) {
            return param;
        }
        byte[] dataLen = new byte[2];
        byte[] dataLen4 = ArrayUtil.intToBytesLittle(param.length);
        System.arraycopy(dataLen4, 0, dataLen, 0, 2);

        byte[] bytes = ArrayUtil.bytesSplic(cmdCode, dataLen, param, new byte[0]);
        return bytes;
    }

    public byte[][] getTotaV2LongPacket(byte[] data, int mtu) {
        int dataLen = mtu - 4 * 4;
        byte[] encodeData = totaEncryptData(data);
        int count = encodeData.length % dataLen == 0 ? encodeData.length / dataLen : encodeData.length / dataLen + 1;
        byte[][] result = new byte[count][];

        for (int i = 0; i < count; i ++) {
            byte[] bytes = new byte[(i == count - 1) ? (encodeData.length - (count - 1) * dataLen) : dataLen];
            System.arraycopy(data, i * dataLen, bytes, 0, bytes.length);
            result[i] = getTotaV2Packet(bytes);
        }
        return result;
    }

    public byte[] setTotaV2PacketData(byte[] receiveData, boolean decode) {
        Log.i("TAG", "setTotaV2PacketData: -----------" + ArrayUtil.toHex(receiveData));
        if (!ArrayUtil.startsWith(receiveData, head) || !ArrayUtil.endWith(receiveData, tail)) {
            return new byte[]{0x00, 0x00, 0x00, 0x00, 0x00};
        }
        System.arraycopy(receiveData, head.length, dataLen, 0, dataLen.length);
        int curDataLen = ArrayUtil.bytesToIntLittle(dataLen);
        byte[] data = new byte[curDataLen];
        System.arraycopy(receiveData, head.length + dataLen.length, data, 0, curDataLen);
        byte[] mCrc = new byte[4];
        long crc32 = ArrayUtil.crc32(data, 0, data.length);
        mCrc[0] = (byte) crc32;
        mCrc[1] = (byte) (crc32 >> 8);
        mCrc[2] = (byte) (crc32 >> 16);
        mCrc[3] = (byte) (crc32 >> 24);
        System.arraycopy(receiveData, head.length + dataLen.length + curDataLen, crc, 0, crc.length);
        //crc
        for (int i = 0; i < crc.length; i ++) {
            if (mCrc[i] != crc[i]) {
                return new byte[]{0x01};
            }
        }
        if (decode) {
            data = totaDecodeData(data);
        }
//        if (cashData.length > 0) {
//            data = ArrayUtil.byteMerger(cashData, data);
//        }
//        byte[] cmdCode = new byte[2];
//        byte[] cmdDataLen = new byte[4];
//        System.arraycopy(data, cmdCode.length, cmdDataLen, 0, 2);
//        int cmdDataLenL = ArrayUtil.bytesToIntLittle(cmdDataLen);
//        Log.i("TAG", "cmdDataLenL:-----------" + cmdDataLenL);
//        if ((cmdDataLenL + cmdCode.length + 2) > data.length) {
//            cashData = data;
//            return new byte[]{0x02};
//        }
//        cashData = new byte[0];
        return data;
//        if (!ArrayUtil.startsWith(receiveData, head)) {
//            receiveData = ArrayUtil.byteMerger(cashReceiveData, receiveData);
//        } else {
//            cashReceiveData = new byte[0];
//        }
//        if (!ArrayUtil.startsWith(receiveData, head)) {
//            return new byte[]{0x00, 0x00, 0x00, 0x00, 0x00};
//        }
//        System.arraycopy(receiveData, head.length, dataLen, 0, dataLen.length);
//        int curDataLen = ArrayUtil.bytesToIntLittle(dataLen);
//        Log.i("TAG", "curDataLen: --------" + curDataLen);
//        int curLen = head.length + dataLen.length + curDataLen + crc.length + tail.length;
//        if (curLen < receiveData.length) {
//            cashReceiveData = new byte[receiveData.length - curLen];
//            System.arraycopy(receiveData, curLen, cashReceiveData, 0, receiveData.length - curLen);
//        }
//
//        byte[] data = new byte[curDataLen];
//        System.arraycopy(receiveData, head.length + dataLen.length, data, 0, curDataLen);
//        byte[] mCrc = new byte[4];
//        long crc32 = ArrayUtil.crc32(data, 0, data.length);
//        mCrc[0] = (byte) crc32;
//        mCrc[1] = (byte) (crc32 >> 8);
//        mCrc[2] = (byte) (crc32 >> 16);
//        mCrc[3] = (byte) (crc32 >> 24);
//        System.arraycopy(receiveData, head.length + dataLen.length + curDataLen, crc, 0, crc.length);
//        //crc
//        for (int i = 0; i < crc.length; i ++) {
//            if (mCrc[i] != crc[i]) {
//                return new byte[]{0x01};
//            }
//        }
//        //data
//        if (cashData.length != 0) {
//            data = ArrayUtil.byteMerger(cashData, data);
//        }
//        if (decode) {
//            data = totaDecodeData(data);
//        }
//        Log.i("TAG", "totaDecodeData: --------" + ArrayUtil.toHex(data));
//        byte[] cmdCode = new byte[2];
//        byte[] cmdDataLen = new byte[4];
//        System.arraycopy(data, cmdCode.length, cmdDataLen, 0, 2);
//        int cmdDataLenL = ArrayUtil.bytesToIntLittle(cmdDataLen);
//        Log.i("TAG", "cmdDataLenL:-----------" + cmdDataLenL);
//        if ((cmdDataLenL + cmdCode.length + 2) > data.length) {
//            cashData = data;
//            return new byte[]{0x02};
//        }
//        return data;
    }

    public int receiveData(byte[] data) {
        Log.i("TAG", "TOTA receiveData: ----------" + ArrayUtil.toHex(data));
        if (data.length < 2) {
            return 0;
        }
        if (data[0] == 0x02 && (data[1] & 0xff) == 0x10) {
            //random_a
            byte[] bytes = new byte[]{data[3],data[2]};
            String bytesStr = ArrayUtil.toHex(bytes);
            int L = Integer.parseInt(bytesStr.replace(",", ""), 16);
            random_a = new byte[L - 1];
            System.arraycopy(data, 5, random_a, 0, L - 1);
            //hash_key_b
            byte[] random = new besFunc().func1(random_a, random_b);
            hash_key_b = Sha256.getSHA256(random);
            aes_key = new besFunc().func(hash_key_b);

            return BesSdkConstants.BES_TOTA_CONFIRM;
        } else if (data[0] == 0x00 && (data[1] & 0xff) == 0x10) {
            if (data.length > 15 && data[12] == 0x73 && data[13] == 0x75 && data[14] == 0x63) {

                return BesSdkConstants.BES_TOTA_SUCCESS;
            } else {

                return BesSdkConstants.BES_TOTA_ERROR;
            }
        }
        return 0;
    }

    public void setAes_key(byte[] data) {
        aes_key = data;
    }

    public byte[] getAes_key() {
        return aes_key;
    }
}
